package cn.huiyunche.base.service.interfaces.impl;

import cn.huiyunche.base.service.form.BFeeProductForm;
import cn.huiyunche.base.service.interfaces.BProductsService;
import cn.huiyunche.base.service.interfaces.GDMapService;
import cn.huiyunche.base.service.mappers.BProductArrivalConfigMapper;
import cn.huiyunche.base.service.mappers.BProductCoefficientMapper;
import cn.huiyunche.base.service.mappers.SUserAddrMapper;
import cn.huiyunche.base.service.mappers.ext.BProductsViewMapper;
import cn.huiyunche.base.service.model.*;
import cn.huiyunche.base.service.vo.BProductCoefficientVo;
import cn.huiyunche.base.service.vo.BProductVo;
import cn.huiyunche.tools.basic.exceptions.BusinessException;
import org.apache.commons.collections4.CollectionUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.List;

@Service
public class BProductsServiceImpl implements BProductsService {

    private static final Logger LOGGER = LoggerFactory.getLogger(BProductsServiceImpl.class);

    @Autowired
    private SUserAddrMapper userAddrMapper;

    @Autowired
    private GDMapService mapService;

    @Autowired
    private BProductsViewMapper productsViewMapper;

    @Autowired
    private BProductArrivalConfigMapper arriveDaysMapper;

    @Autowired
    private BProductCoefficientMapper bProductCoefficientMapper;

    public List<BProductVo> fetchProducts(long depaId, long destId, Date adate, String atime) throws Exception {
        LOGGER.info("fetchProducts params : {}, {}, {}, {}", depaId, destId, adate, atime);
        if (0 == depaId) {
            LOGGER.error("fetchProducts depaId must not be null");
            throw new IllegalArgumentException("提车地址id不能为空！");
        }
        if (0 == destId) {
            LOGGER.error("fetchProducts destId must not be null");
            throw new IllegalArgumentException("交车地址id不能为空！");
        }

        //获取地址信息
        SUserAddr depaAddr = userAddrMapper.selectByPrimaryKey(depaId);
        SUserAddr destAddr = userAddrMapper.selectByPrimaryKey(destId);
        return buildFeeProduct(adate, atime, depaAddr, destAddr);

    }

    public List<BProductVo> fetchProducts(BFeeProductForm feeProductForm) throws Exception {
        LOGGER.info("fetch products parms: {}", feeProductForm);
        if (null == feeProductForm) {
            LOGGER.error("feeProductForm must not be null");
            throw new BusinessException("获取物流产品信息失败！");
        }


        Date adate = feeProductForm.getDepartDate();
        String atime = feeProductForm.getDepartTime();

        SUserAddr depaAddr = new SUserAddr();
        depaAddr.setCityCode(feeProductForm.getDepartCityCode());
        depaAddr.setProvinceName(feeProductForm.getDepartProvinceName());
        depaAddr.setCityName(feeProductForm.getDepartCityName());
        depaAddr.setCountyCode(feeProductForm.getDepartCountyCode());
        depaAddr.setCountyName(feeProductForm.getDepartCountyName());

        SUserAddr destAddr = new SUserAddr();
        destAddr.setCityCode(feeProductForm.getReceiptCityCode());
        destAddr.setProvinceName(feeProductForm.getReceiptProvinceName());
        destAddr.setCityName(feeProductForm.getReceiptCityName());
        destAddr.setCountyCode(feeProductForm.getReceiptCountyCode());
        destAddr.setCountyName(feeProductForm.getReceiptCountyName());

        return buildFeeProduct(adate, atime, depaAddr, destAddr);
    }


    /**
     * 构建物流产品返回列表
     *
     * @param adate
     * @param atime
     * @param depaAddr
     * @param destAddr
     * @return
     */
    private List<BProductVo> buildFeeProduct(Date adate, String atime, SUserAddr depaAddr, SUserAddr destAddr) throws Exception {
        LOGGER.info("buildFeeProduct params : {}, {}, {}, {}", adate, atime, depaAddr, destAddr);
        final BigDecimal distance = mapService.distance(depaAddr.getCountyCode(),
                new StringBuilder(depaAddr.getProvinceName()).append(depaAddr.getCityName())
                        .append(depaAddr.getCountyName()).toString(),
                destAddr.getCountyCode(), new StringBuilder(destAddr.getProvinceName()).append(destAddr.getCityName())
                        .append(destAddr.getCountyName()).toString());

        //查询物流产品
        BProductArrivalConfigExample example = new BProductArrivalConfigExample();
        example.createCriteria().andBeginRangeLessThanOrEqualTo(distance.setScale(0, RoundingMode.UP)).andEndRangeGreaterThanOrEqualTo(distance.setScale(0, RoundingMode.UP));
        List<BProductVo> list = productsViewMapper.selectProductsByConditions(example);
        if (CollectionUtils.isEmpty(list)) {
            LOGGER.error("buildFeeProduct list must not be null");
            throw new IllegalArgumentException("获取物流产品信息失败！");
        } else {
            list.stream().forEach(vo -> {

                //设置运距
                vo.setDistance(distance.setScale(2, RoundingMode.UP));

                //计算运输天数
                BProductArrivalConfig arriveDay = this.getBProductArrivalConfigById(vo.getId());
                vo.setDays(this.computeDays(arriveDay, distance));

                //计算到达时间
                vo.setEndTime(this.computeEstimatedArrivalTime(adate, vo.getDays(), vo.getMaxDays(), vo.getEndTime(), atime));
            });
            return list;
        }
    }

    @Override
    public BProductVo getProduct(long id, BigDecimal distance) {
        LOGGER.info("getProduct params : {}, {}", id, distance);
        if (0 == id) {
            LOGGER.error("getProduct id must not be 0");
            throw new IllegalArgumentException("物流产品id不能为0！");
        }
        BProductVo vo = productsViewMapper.selectProductById(id);

        //计算运输天数
        BProductArrivalConfig arriveDay = this.getBProductArrivalConfigById(vo.getId());
        vo.setDays(this.computeDays(arriveDay, distance));

        return vo;
    }

    @Override
    public BProductCoefficient getProductCoefficientByConditions(long productid, BigDecimal distance) {
        LOGGER.info("getProductCoefficientByConditions params : {}, {}", productid, distance);
        if (0 == productid) {
            LOGGER.error("getProductCoefficientByConditions productid must not be bull");
            throw new IllegalArgumentException("物流产品id不能为空！");
        }
        if (null == distance) {
            LOGGER.error("getProductCoefficientByConditions distance must not be null");
            throw new IllegalArgumentException("运距不能为空！");
        }
        BProductCoefficientExample example = new BProductCoefficientExample();
        example.createCriteria().andProductIdEqualTo(productid).andBeginRangeLessThanOrEqualTo(distance.setScale(0, RoundingMode.UP).intValue()).andEndRangeGreaterThanOrEqualTo(distance.setScale(0, RoundingMode.UP).intValue());
        List<BProductCoefficient> list = bProductCoefficientMapper.selectByExample(example);
        if (CollectionUtils.isEmpty(list)) {
            LOGGER.error("getProductCoefficientByConditions list must not be null");
            throw new BusinessException("获取物流产品价格系数失败！");
        }
        return list.get(0);
    }

    @Override
    public List<BProductCoefficientVo> getCoefficients(BigDecimal distance, Boolean isExpedited, Date startTime, String AMorPM) {
        LOGGER.info("getCoefficients params : {}, {}, {}, {}", distance, isExpedited, startTime, AMorPM);
        if (null == distance) {
            LOGGER.error("getCoefficients distance must not be null");
            throw new IllegalArgumentException("运距不能为空！");
        }
        List<BProductCoefficientVo> list = productsViewMapper.selectCoefficientsByConditions(distance.setScale(0, BigDecimal.ROUND_HALF_UP));
        /*if(null != isExpedited){ // 去除加急物流信息处理
			list = list.stream().filter(vo -> vo.isExpedited()).collect(Collectors.toList());
		}*/
        if (CollectionUtils.isEmpty(list)) {
            LOGGER.error("getCoefficients list is empty");
            throw new BusinessException("查询物流产品价格系数信息失败！");
        }

        //如果有出发日期和时间 则计算到达时
        if (null != startTime && null != AMorPM) {
            list.stream().forEach(vo -> {

                //设置运距
                vo.setDistance(distance.setScale(2, RoundingMode.UP));

                //计算运输天数
                BProductArrivalConfig arriveDay = this.getArriveDays(vo.getProductId(), vo.getEndRange());
                vo.setDays(this.computeDays(arriveDay, distance));

                //计算到达时间
                vo.setEndTime(this.computeEstimatedArrivalTime(startTime, vo.getDays(), vo.getMaxDays(), vo.getEndTime(), AMorPM));
            });
        }
        return list;
    }

    @Override
    public BProductArrivalConfig getArriveDays(Long productId, BigDecimal endRange) {
        LOGGER.info("getArriveDays params : {}, {}", productId, endRange);
        if (null == productId) {
            LOGGER.error("getArriveDays productId must not be null");
            throw new IllegalArgumentException("物流产品id不能为空！");
        }
        if (null == endRange) {
            LOGGER.error("getArriveDays endRange must not be null");
            throw new IllegalArgumentException("预计结束范围不能为空！");
        }
        BProductArrivalConfigExample example = new BProductArrivalConfigExample();
        example.createCriteria().andProductIdEqualTo(productId).andEndRangeGreaterThanOrEqualTo(endRange);
        List<BProductArrivalConfig> list = arriveDaysMapper.selectByExample(example);
        if (CollectionUtils.isEmpty(list)) {
            LOGGER.error("getArriveDays list must not be null");
            throw new BusinessException("获取到达天数信息失败！");
        }
        return list.get(0);
    }

    @Override
    public BProductCoefficient getById(Long id) {
        LOGGER.info("getById param : {}", id);
        return bProductCoefficientMapper.selectByPrimaryKey(id);
    }

    @Override
    public Date computeEstimatedArrivalTime(Date startTime, Integer days, Integer maxDays, Date endTime, String AMorPM) {
        LOGGER.info("computeEstimatedArrivalTime params : {}, {}, {}, {}, {}", startTime, days, maxDays, endTime, AMorPM);
        Calendar cal = GregorianCalendar.getInstance();
        cal.setTime(endTime);

        Calendar ca = GregorianCalendar.getInstance();
        ca.setTime(startTime);
        ca.set(Calendar.HOUR, cal.get(Calendar.HOUR_OF_DAY));
        ca.set(Calendar.MINUTE, cal.get(Calendar.MINUTE));
        ca.set(Calendar.SECOND, cal.get(Calendar.SECOND));
        Integer amOrpm = Integer.valueOf(AMorPM.replaceAll(":", ""));
        //只有计算的运输天数小于最大运输天数时选下午时才可以+1天
        if (null != maxDays) {

            if (amOrpm < 1200) {    //上午
                ca.set(GregorianCalendar.DATE, ca.get(GregorianCalendar.DATE) + days);
            } else {
                if (days < maxDays) {
                    ca.set(GregorianCalendar.DATE, ca.get(GregorianCalendar.DATE) + days + 1);
                } else {
                    ca.set(GregorianCalendar.DATE, ca.get(GregorianCalendar.DATE) + days);
                }
            }
        } else {
            if (amOrpm < 1200) {    //上午
                ca.set(GregorianCalendar.DATE, ca.get(GregorianCalendar.DATE) + days);
            } else {
                ca.set(GregorianCalendar.DATE, ca.get(GregorianCalendar.DATE) + days + 1);
            }

        }
        return ca.getTime();
    }

    @Override
    public Integer computeDays(BProductArrivalConfig arriveDay, BigDecimal distance) {
        LOGGER.info("computeDays params : {}, {}", arriveDay, distance);
        //如果物流产品最小运输天数不为空 则根据需要花费的天数=最小运输天数+（（距离-最小运输天数对应的行驶距离）/ 每天行驶公里数）
        if (null == arriveDay.getDays()) {

            //获取上一个区间设置的最小天数
            BProductArrivalConfig b = this.getArriveDays(arriveDay.getProductId(), !(-1 == arriveDay.getBeginRange().compareTo(BigDecimal.ZERO)) == true ? arriveDay.getBeginRange().subtract(BigDecimal.valueOf(1)) : BigDecimal.ZERO);
            if (null != arriveDay.getMaxDays()) {
                int days = b.getDays() + distance.subtract(b.getEndRange()).divide(BigDecimal.valueOf(arriveDay.getKmPerDay()), 0, RoundingMode.UP).intValue();

                //当计算天数小于最大运输天数时 返回最计算天数 否则返回最大运输天数
                if (arriveDay.getMaxDays() > days) {
                    return days;
                } else {
                    return arriveDay.getMaxDays();
                }
            }
        }
        return arriveDay.getDays();
    }

    @Override
    public BProductArrivalConfig getBProductArrivalConfigById(Long bArriveDaysId) {
        LOGGER.info("getBProductArrivalConfigById param : {}", bArriveDaysId);
        if (null == bArriveDaysId) {
            LOGGER.error("getBProductArrivalConfigById bArriveDaysId must not be null");
            throw new IllegalArgumentException("id不能为空！");
        }
        BProductArrivalConfigExample example = new BProductArrivalConfigExample();
        example.createCriteria().andIdEqualTo(bArriveDaysId);
        List<BProductArrivalConfig> list = arriveDaysMapper.selectByExample(example);
        if (CollectionUtils.isEmpty(list)) {
            LOGGER.error("getBProductArrivalConfigById list must not be null");
            throw new BusinessException("获取到达天数信息失败！");
        }
        return list.get(0);
    }

}
